package fucall

import (
	"fmt"
	"math"
)

func compute(fn func(float64, float64) float64) float64 {
	return fn(3, 4)
}

func funcCall() {
	hypot := func(x, y float64) float64 {
		return math.Sqrt(x*x + y*y)
	}
	fmt.Println(hypot(5, 12))

	fmt.Println(compute(hypot))
	fmt.Println(compute(math.Pow))
}

func calFoo(fn func(int, int) int, a int, b int) int {
	return fn(a, b)
}

func calFn() {
	add := func(a, b int) int {
		return a + b
	}

	minus := func(a, b int) int {
		return a - b
	}

	r := calFoo(add, 3, 4)

	fmt.Println(r)

	r2 := calFoo(minus, 3, 4)

	fmt.Println(r2)
}

func adder() func(int) int {
	sum := 0
	return func(x int) int {
		sum += x
		return sum
	}
}

func fnClosures() {
	pos, neg := adder(), adder()
	for i := 0; i < 10; i++ {
		fmt.Println(
			pos(i),
			neg(-2*i),
		)
	}
}

// fibonacci 是返回一个「返回一个 int 的函数」的函数
func fibonacci() func() int {
	// 初始化斐波那契数列的前两个数
	a, b := 0, 1
	return func() int {
		// 保存当前的 a 值
		result := a
		// 更新 a 和 b 的值
		a, b = b, a+b
		return result
	}
}

func fibo() {
	f := fibonacci()
	for i := 0; i < 10; i++ {
		fmt.Println(f())
	}
}

// 基于 int 类型定义一个新类型
type MyInt int

func pringMyInt() {
	var num MyInt = 10
	fmt.Printf("num 的类型是 %T，值是 %v\n", num, num)
}

// 定义一个函数类型
type Calculator func(int, int) int

// 实现一个加法函数
func add(a, b int) int {
	return a + b
}

// 实现一个减法函数
func subtract(a, b int) int {
	return a - b
}

// 接受一个 Calculator 类型的函数作为参数
func calculate(c Calculator, a, b int) int {
	return c(a, b)
}

func callFuncType() {
	result1 := calculate(add, 5, 3)
	result2 := calculate(subtract, 5, 3)
	fmt.Printf("加法结果: %d\n", result1)
	fmt.Printf("减法结果: %d\n", result2)
}
